from celery import shared_task
from api import models
from utils.encrypt import md5
import uuid
import datetime
import itertools


# Windows下运行celery的命令是这个celery -A auction worker --concurrency=4 --loglevel=INFO -P threads，也就是说要指定是多线程的

@shared_task
def x1(x, y):
    return x + y


@shared_task
def x2(x, y):
    return x * y


@shared_task
def to_preview_status_task(auction_id):
    models.Auction.objects.filter(id=auction_id).update(status=2)
    models.AuctionItem.objects.filter(auction_id=auction_id).update(status=2)


@shared_task
def to_auction_status_task(auction_id):
    models.Auction.objects.filter(id=auction_id).update(status=3)
    models.AuctionItem.objects.filter(auction_id=auction_id).update(status=3)


@shared_task
def end_auction_task(auction_id):
    models.Auction.objects.filter(id=auction_id).update(status=4)
    models.AuctionItem.objects.filter(auction_id=auction_id).update(status=4)

    total = 0
    total_unfortunate_list = []
    lucky_auction_deposit_id = set()
    # 获取专场对象
    auction_object = models.Auction.objects.filter(id=auction_id).first()
    # 获取该专场相关的所有商品对象
    item_object_list = models.AuctionItem.objects.filter(auction=auction_object)

    # 循环所有拍品
    for item_object in item_object_list:
        # 获取当前拍品出价最高者
        lucky_object = models.BidRecord.objects.filter(item=item_object).order_by('-price').first()
        # 判断当前拍品是否有人竞价
        if not lucky_object:
            # 将拍品设置流派
            item_object.status = 5
            item_object.save()
            return
        # 如果存在最高者将当前竞价设置为成交(这里我们的逻辑是全场开始拍品也跟着一起开始)
        lucky_object.status = 2
        lucky_object.save()

        # 拍品：设置成交价
        item_object.deal_price = lucky_object.price
        item_object.save()

        # 专场：总成交额
        total += lucky_object.price

        # 获取当前用户单品保证金
        deposit_object = models.DepositRecord.objects.filter(
            user=lucky_object.user,
            item=item_object,
            deposit_type=1
        ).first()
        # 如果没有单品保证金就去判断全场保证金
        if not deposit_object:
            deposit_object = models.DepositRecord.objects.filter(
                user=lucky_object.user,
                auction_id=auction_id,
                deposit_type=2, item__isnull=True).first()
            # 将当前拍到用户的全场保证金id记录到时候返还时可以通过查询in排除
            lucky_auction_deposit_id.add(deposit_object.id)
        # 给最高出价者生成订单
        order_object = models.Order.objects.create(
            status=1,
            uid=md5(str(uuid.uuid4())),
            user=lucky_object.user,
            item=item_object,
            deposit=deposit_object,
            price=lucky_object.price,
        )
        # 单品保证金：所有没有拍到商品 & 缴纳的是单品保证金记录
        item_unfortunate_list = models.DepositRecord.objects.filter(item=item_object, deposit_type=1).exclude(
            user=lucky_object.user)
        # 将没拍到拍品的人存入(后面还需判断是否还有其他拍品没拍)
        total_unfortunate_list.extend(item_unfortunate_list)

        # 调用定时任务：24小时内要支付,否则流拍扣除保证金.(注意：utc时间)
        date = datetime.datetime.utcnow() + datetime.timedelta(hours=24)
        # date = datetime.datetime.utcnow() + datetime.timedelta(minutes=1)
        task_id = twenty_four_hour.apply_async(args=[order_object.id], eta=date).id
        order_object.twenty_four_task_id = task_id
        order_object.save()

    # 专场：更新成交额
    auction_object.total_price = total
    auction_object.save()
    # 未拍到任何商品的用户的全场保证金
    auction_unfortunate_list = models.DepositRecord.objects.filter(
        deposit_type=2,
        auction=auction_object,
        item__isnull=True).exclude(id__in=lucky_auction_deposit_id)
    # 退保证金（原路退还）itertools.chain=循环这传入的2个对象列表
    for deposit in itertools.chain(total_unfortunate_list, auction_unfortunate_list):
        uid = md5(str(uuid.uuid4()))  # 正确，
        if deposit.pay_type == 1:  # 微信
            # res = refund(uid, deposit.uid, deposit.amount, deposit.amount)
            res = True
            models.DepositRefundRecord.objects.create(
                uid=uid,
                status=2 if res else 1,
                amount=deposit.amount,
                deposit=deposit
            )
            if res:
                deposit.balance = 0
                deposit.save()
        else:  # 余额
            deposit.user.balance += deposit.amount
            deposit.user.save()
            models.DepositRefundRecord.objects.create(
                uid=uid,
                status=2,
                amount=deposit.amount,
                deposit=deposit
            )
            deposit.balance = 0
            deposit.save()
    # 拍卖结束之后，将在之后的第24小时将所有 未使用 的用户优惠券主动过期
    date = datetime.datetime.utcnow() + datetime.timedelta(hours=24)
    user_coupon_to_expired.apply_async(args=[auction_id], eta=date)


@shared_task
def twenty_four_hour(order_id):
    """24小时未支付的逾期处理"""
    order_object = models.Order.objects.filter(id=order_id).first()
    # 订单已支付
    if order_object.status != 1:
        return
    # 订单逾期
    order_object.status = 4
    order_object.save()
    # 拍品状态逾期
    order_object.item.status = 6
    order_object.item.save()

    # 单品保证金，直接扣除
    if order_object.deposit.deposit_type == 1:
        # 单品保证金
        order_object.deposit.balance = 0
        order_object.deposit.save()
        # 生成一个记录
        models.DepositDeduct.objects.create(order=order_object, amount=order_object.deposit.amount)
        return
        # 全场保证金，扣除(如果全场保证金余额不足以当前拍品直接赋0)
    if order_object.deposit.balance <= order_object.item.deposit:
        order_object.deposit.balance = 0
        order_object.deposit.save()
        # 生成记录
        models.DepositDeduct.objects.create(order=order_object, amount=order_object.deposit.balance)
        return

        # 全场保证金足够的情况(扣除单品保证金)
    order_object.deposit.balance -= order_object.item.deposit
    order_object.deposit.save()
    # 扣除完成后,生成一个扣除单品金额记录
    models.DepositDeduct.objects.create(order=order_object, amount=order_object.item.deposit)
    # 检查此专场是否还有其他订单未支付
    exists = models.Order.objects.filter(user=order_object.user, status=1,
                                         item__auction=order_object.deposit.auction).exclude(id=order_id).exists()
    # 有就先不还款,没有就还款
    if exists:
        return
    # 生成订单号
    uid = md5(uuid.uuid4())
    # 微信退款
    if order_object.deposit.pay_type == 1:
        # 微信还款功能(没做,成功后会返回True)
        # res = refund(uid, deposit.uid, deposit.amount, deposit.amount)
        res = True
        # 保证金退款记录
        models.DepositRefundRecord.objects.create(
            uid=uid,
            status=2 if res else 1,
            amount=order_object.deposit.balance,
            deposit=order_object.deposit
        )
        if res:
            order_object.deposit.balance = 0
            order_object.deposit.save()
    else:  # 余额
        order_object.deposit.user.balance += order_object.deposit.balance
        order_object.deposit.user.save()
        # 生成退款记录
        models.DepositRefundRecord.objects.create(
            uid=uid,
            status=2,
            amount=order_object.deposit.balance,
            deposit=order_object.deposit
        )
        # 清空全场保证金余额保存
        order_object.deposit.balance = 0
        order_object.deposit.save()


@shared_task
def coupon_start_apply(coupon_id):
    models.Coupon.objects.filter(id=coupon_id, status=1).update(status=2)


@shared_task
def coupon_stop_apply(coupon_id):
    models.Coupon.objects.filter(id=coupon_id, status=2).update(status=3)


@shared_task
def user_coupon_to_expired(auction_id):
    models.UserCoupon.objects.filter(coupon__auction_id=auction_id, status=1).update(status=3)
